#import "FlutterBleOtaPlugin.h"
#import "JL_RunSDK.h"


const NSString *kInitString = @"initOTA";
const NSString *kConnectString = @"connectDevice";
const NSString *kStartString = @"startOTA";
const NSString *kDisposeString = @"dispose";


/// native to flutter
NSString *kOtaStartString = @"otaStart";
NSString *kOtaCancelString = @"otaCancel";
NSString *kOtaStopString = @"otaStop";

@interface FlutterBleOtaPlugin ()<JL_RunSDKOtaDelegate, FlutterStreamHandler>

@property (nonatomic, strong) JL_RunSDK *sdkManager;
@property (nonatomic, copy) FlutterResult connectResult;
@property (nonatomic, strong) FlutterMethodChannel *methodChannel;
@property (nonatomic, strong) FlutterEventChannel *eventChannel;
@property (nonatomic, copy) FlutterEventSink eventSink;

@end

@implementation FlutterBleOtaPlugin


- (instancetype)initWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
    if (self = [super init]) {
        _methodChannel = [FlutterMethodChannel
                                         methodChannelWithName:@"flutter_ble_ota"
                                         binaryMessenger:[registrar messenger]];
        _eventChannel = [FlutterEventChannel eventChannelWithName:@"flutter_ble_ota_event" binaryMessenger:registrar.messenger];
        [_eventChannel setStreamHandler:self];
    }
    
    return self;
}


+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
    FlutterBleOtaPlugin* instance = [[FlutterBleOtaPlugin alloc] initWithRegistrar:registrar];
    [registrar addMethodCallDelegate:instance channel:instance.methodChannel];
}

- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
    if ([@"getPlatformVersion" isEqualToString:call.method]) {
        result([@"iOS " stringByAppendingString:[[UIDevice currentDevice] systemVersion]]);
    } else if ([kInitString isEqualToString:call.method]) {
        [self initSDKWithResult:result];
    } else if ([kConnectString isEqualToString:call.method]) {
        [self connectWithUUID:call.arguments result:result];
    } else if ([kStartString isEqualToString:call.method]) {
        [self updateOTAWithPath:call.arguments result:result];
    } else if ([kDisposeString isEqualToString:call.method]) {
        [self disposeWithResult:result];
    } else {
        result(FlutterMethodNotImplemented);
    }
}

- (void)initSDKWithResult:(FlutterResult)result {
    self.sdkManager = [JL_RunSDK sharedInstance];
    self.sdkManager.otaDelegate = self;
    result(@(YES));
}

- (void)connectWithUUID:(NSString *)uuid result:(FlutterResult)result {
    self.connectResult = result;
    [self.sdkManager startLoopConnect:uuid];
}

- (void)updateOTAWithPath:(NSString *)path result:(FlutterResult)result {
    [self.sdkManager otaFuncWithFilePath:path];
    [self.methodChannel invokeMethod:kOtaStartString arguments:nil];
    result(@(YES));
}

- (void)disposeWithResult:(FlutterResult)result {
    result(@(YES));
//    [self.sdkManager disposeWithCallback:^(BOOL isDisconnect) {
//        result(@(isDisconnect));
//    }];
}


#pragma mark - JL_RunSDKOtaDelegate
- (void)otaProgressWithOtaResult:(JL_OTAResult)result withProgress:(float)progress {
    BOOL isFailed = YES;
    switch (result) {
        case JL_OTAResultSuccess:
            isFailed = NO;
            [self.methodChannel invokeMethod:kOtaStopString arguments:nil];
            break;
            
        case JL_OTAResultUpgrading:
        case JL_OTAResultPreparing:
            isFailed = NO;
            if (self.eventSink) {
                self.eventSink(@{@"status": @(1), @"type": @(1), @"progress": @(progress * 100)});
            }
            break;
            
        case JL_OTAResultReconnect:
        case JL_OTAResultReboot:
        case JL_OTAResultPrepared:
            isFailed = NO;
            break;
            
        default:
            break;
    }
    
    if (isFailed && self.eventSink) {
        self.eventSink(@{@"status": @(2), @"code": @(result), @"msg": @"update failed"});
    }
}

- (void)connectStatus:(JL_EntityM_Status)status {
    NSLog(@"conect status: %@", @(status));
    if (self.connectResult) {
        BOOL result = status == JL_EntityM_StatusPaired;
        self.connectResult(@(result));
    }
}

#pragma mark - FlutterStreamHandler
- (FlutterError *)onListenWithArguments:(id)arguments eventSink:(FlutterEventSink)events {
    _eventSink = events;
    return nil;
}

- (FlutterError *)onCancelWithArguments:(id)arguments {
    _eventSink = nil;
    return nil;
}

- (void)getDeviceInfoFailed:(JL_CMDStatus)status {
    self.eventSink(@{@"status": @(2), @"code": @(status), @"msg": @"get device info failed"});
}

@end
